////////////////////////////////////////////////////////////////////////////
//
//  Crytek Engine Source File.
//  Copyright (C), Crytek Studios, 2001.
// -------------------------------------------------------------------------
//  File name:   IEditorImpl.cpp
//  Version:     v1.00
//  Created:     10/10/2001 by Timur.
//  Compilers:   Visual C++ 6.0
//  Description: CEditorImpl class implementation.
// -------------------------------------------------------------------------
//  History:
//
////////////////////////////////////////////////////////////////////////////

#include "StdAfx.h"
#include "IEditorImpl.h"
#include "CryEdit.h"
#include "CryEditDoc.h"
#include "CustomColorDialog.h"
#include "Plugin.h"
#include "ResourceCompilerHelper.h"

#include "PluginManager.h"
#include "IconManager.h"
#include "ViewManager.h"
#include "ViewPane.h"
#include "Objects\GizmoManager.h"
#include "Objects\AxisGizmo.h"
#include "DisplaySettings.h"
#include "ShaderEnum.h"
#include "EAXPresetMgr.h"
#include "SoundMoods\SoundMoodMgr.h"
#include "HyperGraph\FlowGraphManager.h"
#include "HyperGraph\FlowGraphModuleManager.h"
#include "HyperGraph\FlowGraphDebuggerEditor.h"

#include "EquipPackLib.h"
#include "AI\AIManager.h"
#include "UI\UIManager.h"
#include "Material\MaterialFXGraphMan.h"
#include "Undo\Undo.h"
#include "Material\MaterialManager.h"
#include "Material\MaterialPickTool.h"
#include "EntityPrototypeManager.h"
#include "AnimationContext.h"
#include "GameEngine.h"
#include "ToolBox.h"
#include "BaseLibraryDialog.h"
#include "Material\Material.h"
#include "EntityPrototype.h"
#include "Particles\ParticleManager.h"
#include "Music\MusicManager.h"
#include "Prefabs\PrefabManager.h"
#include "GameTokens\GameTokenManager.h"
#include "Util\SourceControlInterface.h"
#include "DataBaseDialog.h"
#include "LightmapCompiler\SceneContext.h"
#include "UIEnumsDatabase.h"
#include "Util\Ruler.h"
#include "Script\ScriptEnvironment.h"
#include "LevelIndependentFileMan.h"
#include "SegmentedWorld\SegmentedWorldManager.h"

//////////////////////////////////////////////////////////////////////////
// Tools.
//////////////////////////////////////////////////////////////////////////
#include "PickObjectTool.h"
#include "ObjectCreateTool.h"
#include "TerrainModifyTool.h"
#include "VegetationTool.h"
#include "EditMode\ObjectMode.h"
#include "EditMode\VertexMode.h"
#include "TerrainVoxelTool.h"

#include "Brush\BrushClipTool.h"
#include "Brush\BrushTextureTool.h"
#include "Brush\SolidBrushObject.h"

#include "PhotonTool.h"
#include "PhotonViewTool.h"
#include "FacialEditor/FacialEditorDialog.h"

#include "Modelling\PolygonTool.h"
#include "Modelling\ModellingMode.h"

#include "Terrain/TerrainManager.h"
#include "Console/ConsoleSync.h"

#include "BSTEditor/SelectionTreeManager.h"

//////////////////////////////////////////////////////////////////////////
#include <I3DEngine.h>
#include <IConsole.h>
#include <IEntitySystem.h>
#include <IMovieSystem.h>

#pragma comment(lib, "version.lib")

//////////////////////////////////////////////////////////////////////////
// Pointer to global document instance.
//////////////////////////////////////////////////////////////////////////
static CCryEditDoc* theDocument;

static IEditor* s_pEditor = NULL;
//////////////////////////////////////////////////////////////////////////
SANDBOX_API IEditor* GetIEditor()
{
	return s_pEditor;
}

//////////////////////////////////////////////////////////////////////////
static CMainFrame* GetMainFrame()
{
	CWnd *pWnd = AfxGetMainWnd();
	if (!pWnd)
		return 0;
	if (!pWnd->IsKindOf(RUNTIME_CLASS(CMainFrame)))
		return 0;
	return (CMainFrame*)AfxGetMainWnd();
}

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CEditorImpl::CEditorImpl()
: m_bInitialized(false)
{
	s_pEditor = this;
	m_system = 0;

	m_currEditMode = eEditModeSelect;
	m_prevEditMode = m_currEditMode;
	m_pEditTool = 0;
	m_pSettingsManager = 0;

	m_pLevelIndependentFileMan = new CLevelIndependentFileMan;

	SetMasterCDFolder();

	gSettings.Load();

	m_gameEngine = 0;
	m_bExiting = false;
	m_pErrorReport = new CErrorReport;
	m_pLasLoadedLevelErrorReport =  NULL;
	m_classFactory = CClassFactory::Instance();
	m_pCommandManager = new CCommandManager;

	CRegistrationContext regCtx;
	regCtx.pCommandManager = m_pCommandManager;
	regCtx.pClassFactory = m_classFactory;
	m_pConsoleSync = 0;
	m_pUIEnumsDatabase = new CUIEnumsDatabase;
	m_displaySettings = new CDisplaySettings;
	m_shaderEnum = new CShaderEnum;
	m_displaySettings->LoadRegistry();
	m_pluginMan = new CPluginManager;
	m_objectMan = new CObjectManager;
	m_viewMan = new CViewManager;
	m_iconManager = new CIconManager;
	m_undoManager = new CUndoManager;
	m_pEAXPresetMgr = new CEAXPresetMgr;
	m_pSoundMoodMgr = new CSoundMoodMgr;
	m_pAI = new CAIManager;
	m_pUIManager = new CUIManager;
	m_animationContext = new CAnimationContext;
	m_pEquipPackLib = new CEquipPackLib;
	m_pToolBoxManager = new CToolBoxManager;
	m_materialManager = new CMaterialManager(regCtx);
	m_entityManager = new CEntityPrototypeManager;
	m_particleManager = new CParticleManager;
	m_pMusicManager = new CMusicManager;
	m_pPrefabManager = new CPrefabManager;
	m_pGameTokenManager = new CGameTokenManager;

	m_pFlowGraphManager = new CFlowGraphManager;
	m_pFlowGraphModuleManager = new CEditorFlowGraphModuleManager;
	m_pFlowGraphDebuggerEditor	= new CFlowGraphDebuggerEditor;
	m_pMatFxGraphManager = new CMaterialFXGraphMan;

	m_pSourceControl = new CSourceControlInterface;

	m_pSelectionTreeManager = new CSelectionTreeManager;

	m_scriptEnv = new EditorScriptEnvironment();
	m_pLightMapperSceneCtx = new CSceneContext;
	m_pRuler = new CRuler;

	m_marker(0,0,0);
	m_selectedRegion.min=Vec3(0,0,0);
	m_selectedRegion.max=Vec3(0,0,0);

	m_selectedAxis = AXIS_TERRAIN;
	m_refCoordsSys = COORDS_LOCAL;

	ZeroStruct(m_lastAxis);
	m_lastAxis[eEditModeSelect] = AXIS_TERRAIN;
	m_lastAxis[eEditModeSelectArea] = AXIS_TERRAIN;
	m_lastAxis[eEditModeMove] = AXIS_TERRAIN;
	m_lastAxis[eEditModeRotate] = AXIS_Z;
	m_lastAxis[eEditModeScale] = AXIS_XY;

	ZeroStruct(m_lastCoordSys);
	m_lastCoordSys[eEditModeSelect] = COORDS_LOCAL;
	m_lastCoordSys[eEditModeSelectArea] = COORDS_LOCAL;
	m_lastCoordSys[eEditModeMove] = COORDS_VIEW;
	m_lastCoordSys[eEditModeRotate] = COORDS_LOCAL;
	m_lastCoordSys[eEditModeScale] = COORDS_LOCAL;

	m_bAxisVectorLock = false;
	m_bUpdates = true;

	DetectVersion();

	m_bSelectionLocked = true;
	m_bTerrainAxisIgnoreObjects = false;

	RegisterTools();

	m_pickTool = 0;
	m_pAxisGizmo = 0;

	m_bMatEditMode = false;

	doc_use_subfolder_for_crash_backup = 0;
}

//////////////////////////////////////////////////////////////////////////
CEditorImpl::~CEditorImpl()
{
//	if (m_movieSystem)
//		delete m_movieSystem;

	gSettings.Save();

	m_bExiting = true; // Can't save level after this point (while Crash)

	SAFE_DELETE( m_scriptEnv );
	SAFE_DELETE( m_pSourceControl );
	SAFE_DELETE( m_pPrefabManager );
	SAFE_DELETE( m_pGameTokenManager );

	SAFE_DELETE(m_pMatFxGraphManager);
	SAFE_DELETE(m_pFlowGraphModuleManager);

	if(m_pFlowGraphDebuggerEditor)
	{
			m_pFlowGraphDebuggerEditor->Shutdown();
			SAFE_DELETE(m_pFlowGraphDebuggerEditor);
	}
	
	SAFE_DELETE( m_pFlowGraphManager );
	SAFE_DELETE( m_pSelectionTreeManager );

	CTerrainManager::ShutDown();

	SAFE_DELETE(m_pMusicManager)
	SAFE_DELETE(m_particleManager)
	SAFE_DELETE(m_entityManager)

	m_materialManager->Set3DEngine(NULL);
	SAFE_DELETE(m_materialManager)
	SAFE_DELETE(m_pUIManager)
	SAFE_DELETE(m_pEquipPackLib)
	SAFE_DELETE(m_undoManager)
	SAFE_DELETE(m_iconManager)
	SAFE_DELETE(m_pEAXPresetMgr)
	SAFE_DELETE(m_viewMan)
	SAFE_DELETE(m_objectMan)
	// AI should be destroyed after the object manager, as the objects may
	// refer to AI components.
	SAFE_DELETE(m_pAI)

	SAFE_DELETE(m_pluginMan)
	SAFE_DELETE(m_animationContext)

	if (m_displaySettings)
		m_displaySettings->SaveRegistry();

	SAFE_DELETE(m_displaySettings)
	SAFE_DELETE(m_pLightMapperSceneCtx)
	SAFE_DELETE(m_pRuler)
	SAFE_DELETE(m_shaderEnum)
	SAFE_DELETE(m_pToolBoxManager)
	SAFE_DELETE(m_pCommandManager)
	SAFE_DELETE(m_classFactory)
	SAFE_DELETE(m_pLasLoadedLevelErrorReport)
	SAFE_DELETE(m_pUIEnumsDatabase)
	SAFE_DELETE(m_pConsoleSync);
	SAFE_DELETE(m_pSettingsManager);
#ifndef DISABLE_VICON
	SAFE_DELETE(m_ViconClient);
#endif
	// Game engine should be among the last things to be destroyed, as it 
	// destroys the engine.
	SAFE_DELETE(m_gameEngine)
	SAFE_DELETE(m_pLevelIndependentFileMan);

	// The error report must be destroyed after the game, as the engine
	// refers to the error report and the game destroys the engine.
	SAFE_DELETE(m_pErrorReport)
	SAFE_DELETE(m_pLevelIndependentFileMan);
}

//////////////////////////////////////////////////////////////////////////
void CEditorImpl::SetMasterCDFolder()
{
#ifdef WIN32
	WCHAR sFolder[_MAX_PATH];

	GetModuleFileNameW( GetModuleHandle(NULL), sFolder, sizeof(sFolder));
	PathRemoveFileSpecW(sFolder);

	// Remove Bin32/Bin64 folder.
	WCHAR *lpPath = StrStrIW(sFolder,L"\\Bin32");
	if (lpPath)
		*lpPath = 0;
	lpPath = StrStrIW(sFolder,L"\\Bin64");
	if (lpPath)
		*lpPath = 0;

	m_masterCDFolder = sFolder;
	if (!m_masterCDFolder.IsEmpty())
	{
		if (m_masterCDFolder[m_masterCDFolder.GetLength()-1] != L'\\')
			m_masterCDFolder += L'\\';
	}

	SetCurrentDirectoryW( sFolder );
#endif
}

//////////////////////////////////////////////////////////////////////////
void CEditorImpl::SetGameEngine( CGameEngine *ge )
{
	m_system = ge->GetSystem();
	m_gameEngine = ge;
	
	if (m_pEAXPresetMgr)
		m_pEAXPresetMgr->Load();
	
	if (m_pSoundMoodMgr)
		m_pSoundMoodMgr->Load();

	m_templateRegistry.LoadTemplates( Path::MakeFullPath("Editor") );
	m_objectMan->LoadClassTemplates( Path::MakeFullPath("Editor") );

	m_materialManager->Set3DEngine( ge->GetSystem()->GetI3DEngine() );
	m_animationContext->Init();
}

//////////////////////////////////////////////////////////////////////////
// Call registrations.
//////////////////////////////////////////////////////////////////////////
void CEditorImpl::RegisterTools()
{
	CRegistrationContext rc;
	rc.pCommandManager = m_pCommandManager;
	rc.pClassFactory = m_classFactory;

	//////////////////////////////////////////////////////////////////////////
	// Register various tool classes and commands.
	CTerrainModifyTool::RegisterTool( rc );
	CVegetationTool::RegisterTool( rc );
	CObjectMode::RegisterTool( rc );
	CSubObjectModeTool::RegisterTool( rc );

	CPhotonTool::RegisterTool( rc );
	CPhotonViewTool::RegisterTool( rc );
	CBrushClipTool::RegisterTool( rc );
	CBrushTextureTool::RegisterTool( rc );
	CSolidBrushObject::RegisterCommands( rc );
	CMaterialPickTool::RegisterTool( rc );
	CTerrainVoxelTool::RegisterTool( rc );
	CPolygonTool::RegisterTool( rc );
	CModellingModeTool::RegisterTool( rc );
}

//////////////////////////////////////////////////////////////////////////
void CEditorImpl::ExecuteCommand( const char *sCommand,... )
{
	const size_t BUF_SIZE = 1024;
	char buffer[BUF_SIZE];
	buffer[BUF_SIZE-1] = '\0';

	va_list args;
	va_start(args, sCommand);
	vsprintf_s(buffer, BUF_SIZE, sCommand, args);
	va_end(args);

	m_pCommandManager->Execute( buffer );
}
//////////////////////////////////////////////////////////////////////////
void CEditorImpl::Update()
{
	if (!m_bUpdates)
		return;
	
	FUNCTION_PROFILER( GetSystem(),PROFILE_EDITOR );

	m_pRuler->Update();

	//@FIXME: Restore this latter.
	//if (GetGameEngine() && GetGameEngine()->IsLevelLoaded())
	{	
		m_animationContext->Update();
		m_objectMan->Update();
	}
	if (IsInPreviewMode())
	{
		SetModifiedFlag(FALSE);
		SetModifiedModule(eModifiedNothing);
	}

#ifndef DISABLE_VICON
	//////////////////////////////////////////////////////////////////////////
	if (m_ViconClient)
	{
		m_ViconClient->Update();	
	}
	//////////////////////////////////////////////////////////////////////////
#endif
}

//////////////////////////////////////////////////////////////////////////
ISystem* CEditorImpl::GetSystem()
{
	return m_system;
}

//////////////////////////////////////////////////////////////////////////
I3DEngine* CEditorImpl::Get3DEngine()
{
	if (gEnv)
		return gEnv->p3DEngine;
	return 0;
}

//////////////////////////////////////////////////////////////////////////	
IRenderer*	CEditorImpl::GetRenderer()
{
	if (gEnv)
		return gEnv->pRenderer;
	return 0;
}

//////////////////////////////////////////////////////////////////////////
IGame*	CEditorImpl::GetGame()
{
	if (gEnv)
		return gEnv->pGame;
	return 0;
}

IEditorClassFactory* CEditorImpl::GetClassFactory()
{
	return m_classFactory;
}

//////////////////////////////////////////////////////////////////////////
CCryEditDoc* CEditorImpl::GetDocument()
{
	/*
	CFrameWnd *wnd = dynamic_cast<CFrameWnd*>( AfxGetMainWnd() );
	if (wnd)
		return dynamic_cast<CCryEditDoc*>(wnd->GetActiveDocument());
		*/
	return theDocument;
}
//////////////////////////////////////////////////////////////////////////
const CCryEditDoc* CEditorImpl::GetDocument() const
{
	/*
	CFrameWnd *wnd = dynamic_cast<CFrameWnd*>( AfxGetMainWnd() );
	if (wnd)
	return dynamic_cast<CCryEditDoc*>(wnd->GetActiveDocument());
	*/
	return theDocument;
}
//////////////////////////////////////////////////////////////////////////
void CEditorImpl::SetDocument( CCryEditDoc *pDoc )
{
	theDocument = pDoc;
}

//////////////////////////////////////////////////////////////////////////
void CEditorImpl::SetModifiedFlag( bool modified )
{
	if (GetDocument())
	{
		GetDocument()->SetModifiedFlag(modified);

		if (modified)
		{
			GetDocument()->SetLevelExported(false);
		}
	}
}
//////////////////////////////////////////////////////////////////////////
void CEditorImpl::SetModifiedModule(EModifiedModule	eModifiedModule,bool boSet)
{
	if (GetDocument())
	{
		GetDocument()->SetModifiedModules(eModifiedModule,boSet);
	}
}
//////////////////////////////////////////////////////////////////////////
int	 CEditorImpl::GetModifiedModules()
{
	if (GetDocument())
	{
		return GetDocument()->GetModifiedModule();
	}
	return 0;
}
//////////////////////////////////////////////////////////////////////////
bool CEditorImpl::IsLevelExported() const
{
	const CCryEditDoc*	pDoc(GetDocument());
	if (pDoc)
	{
		return pDoc->IsLevelExported();
	}
	return false;
}
//////////////////////////////////////////////////////////////////////////
bool CEditorImpl::SetLevelExported(bool boExported)
{
	if (GetDocument())
	{
		GetDocument()->SetLevelExported(boExported);
		return true;
	}
	return false;
}
//////////////////////////////////////////////////////////////////////////
bool CEditorImpl::IsModified()
{
	if (GetDocument())
	{
		return GetDocument()->IsModified();
	}
	return false;
}

//////////////////////////////////////////////////////////////////////////
bool CEditorImpl::SaveDocument()
{
	if(m_bExiting)
		return false;

	if (GetDocument())
		return GetDocument()->Save();
	else
		return false;
}

bool CEditorImpl::SaveDocumentBackup()
{
	if(m_bExiting)
		return false;

	const char* const CRASH_FOLDER = "\\.CRASH_BACKUP\\";
	const char* const CRASH_FILE_PREFIX = "CRASH_BACKUP_";

	if(CCryEditDoc* pDocument = GetDocument())
	{
		bool bShouldCreateBackup = true;
		if (doc_use_subfolder_for_crash_backup)
		{
			CString sLevelFolder = pDocument->GetPathName(); // copy the CString so we can modify it
			if (sLevelFolder.GetLength() != 0)
			{
				IObjectManager* pObjectManager = GetObjectManager();
				if (!pObjectManager)
				{
					return false;
				}

				CObjectLayerManager* pObjectLayerManager = pObjectManager->GetLayersManager();
				if (!pObjectLayerManager)
				{
					return false;
				}

				char* szLevelFolder = sLevelFolder.GetBuffer(0); // get the modifiable string buffer
				::PathRemoveFileSpec(szLevelFolder); // remove the filename and extension, leaving the folder
				sLevelFolder.ReleaseBuffer();
				sLevelFolder.Append(CRASH_FOLDER);
				szLevelFolder = sLevelFolder.GetBuffer(0);

				if (::CreateDirectory(szLevelFolder, NULL) || (GetLastError() == ERROR_ALREADY_EXISTS))
				{
					CString oldLayerPath = pObjectLayerManager->GetLayersPath();
					CString newLayerPath(CRASH_FOLDER);
					newLayerPath.Append(oldLayerPath);
					pObjectLayerManager->SetLayersPath(newLayerPath); // make sure layers are saved in the crash folder, not the current folder
					CString fullLayerPath(szLevelFolder);
					fullLayerPath.Append(oldLayerPath);
					if (::CreateDirectory(fullLayerPath.GetBuffer(0), NULL) || (GetLastError() == ERROR_ALREADY_EXISTS))
					{
						CString sLevelName = pDocument->GetPathName(); // copy the CString so we can modify it
						char* szLevelName = sLevelName.GetBuffer(0);
						::PathStripPath(szLevelName); // remove the folder, leaving only the filename and extension

						char szCrashBackupName[MAX_PATH];
						sprintf_s(szCrashBackupName, "%s%s%s", szLevelFolder, CRASH_FILE_PREFIX, szLevelName);

						sLevelName.ReleaseBuffer();

						pDocument->SetPathName(szCrashBackupName, false);
					}
					else
					{
						bShouldCreateBackup = false;
					}

					fullLayerPath.ReleaseBuffer();

					pObjectLayerManager->SetLayersPath(oldLayerPath);
				}
				else
				{
					bShouldCreateBackup = false;
				}

				sLevelFolder.ReleaseBuffer();
			}
		}

		if (bShouldCreateBackup)
		{
			return pDocument->Save();
		}
	}

	return false;
}

//////////////////////////////////////////////////////////////////////////
CStringW CEditorImpl::GetMasterCDFolder()
{ 
	return m_masterCDFolder;
}

//////////////////////////////////////////////////////////////////////////
CString CEditorImpl::GetLevelFolder()
{
	return GetGameEngine()->GetLevelPath();
}

//////////////////////////////////////////////////////////////////////////
CString CEditorImpl::GetSearchPath( EEditorPathName path )
{
	return gSettings.searchPaths[path][0];
}

//////////////////////////////////////////////////////////////////////////
const char* CEditorImpl::GetUserFolder()
{
	m_userFolder = Path::GetUserSandboxFolder();
	return m_userFolder;
}

//////////////////////////////////////////////////////////////////////////
void CEditorImpl::SetDataModified()
{ 
	GetDocument()->SetModifiedFlag(TRUE); 
}

//////////////////////////////////////////////////////////////////////////
bool CEditorImpl::AddMenuItem(uint8 iId, bool bIsSeparator,
																				 eMenuInsertLocation eParent, 
																				 IUIEvent *pIHandler)
{
	//////////////////////////////////////////////////////////////////////
	// Adds a plugin menu item and binds an event handler to it
	//////////////////////////////////////////////////////////////////////
	/*

	PluginIt it;
	CMenu *pMainMenu = NULL;
	CMenu *pLastPluginMenu = NULL;
	DWORD dwMenuID;

	IPlugin *pIAssociatedPlugin = GetPluginManager()->GetAssociatedPlugin();
	uint8 iAssociatedPluginUIID = GetPluginManager()->GetAssociatedPluginUIID();

	ASSERT(!IsBadReadPtr(pIAssociatedPlugin, sizeof(IPlugin)));
	if (!bIsSeparator)
		ASSERT(!IsBadReadPtr(pIHandler, sizeof(IUIEvent)));

	if (pIAssociatedPlugin == NULL || pIHandler == NULL)
		return false;

	// Get the main menu
	pMainMenu = AfxGetMainWnd()->GetMenu();
	ASSERT(pMainMenu);

	// Create the menu ID. The first 8 bits of the upper 16 bits contain the
	// UI ID of the plugin which owns the UI element, the second 8 bits
	// contain the user interface element ID. Set the lower 16 bits to
	// a high number in order to avoid conflicts
	dwMenuID = (iAssociatedPluginUIID | (iId << 8)) | 0xFFFF0000;
	
	switch (eParent)
	{
		// Custom plugin menu
		case eMenuPlugin:
			pLastPluginMenu = pMainMenu->GetSubMenu(pMainMenu->GetMenuItemCount() - 1);
			break;
		// Pre-defined editor menus
		case eMenuFile:
			pLastPluginMenu = pMainMenu->GetSubMenu(FindMenuItem(pMainMenu, "&File"));
			break;
		case eMenuEdit:
			pLastPluginMenu = pMainMenu->GetSubMenu(FindMenuItem(pMainMenu, "&Edit"));
			break;
		case eMenuInsert:
			pLastPluginMenu = pMainMenu->GetSubMenu(FindMenuItem(pMainMenu, "&Insert"));
			break;
		case eMenuGenerators:
			pLastPluginMenu = pMainMenu->GetSubMenu(FindMenuItem(pMainMenu, "&Generators"));
			break;
		case eMenuScript:
			pLastPluginMenu = pMainMenu->GetSubMenu(FindMenuItem(pMainMenu, "&Script"));
			break;
		case eMenuView:
			pLastPluginMenu = pMainMenu->GetSubMenu(FindMenuItem(pMainMenu, "&View"));
			break;
		case eMenuHelp:
			pLastPluginMenu = pMainMenu->GetSubMenu(FindMenuItem(pMainMenu, "&Help"));
			break;
		// Unknown identifier or parent ID passed
		default:
			CLogFile::WriteLine("AddMenuItem(): Unknown parent menu ID passed, incompatible plugin version ?");
			break;
	}

	// Add an menu item to the menu

	ASSERT(pLastPluginMenu);

	if (pLastPluginMenu)
	{
		// Insert the menu
		if (!pLastPluginMenu->AppendMenu(MF_STRING | bIsSeparator ? MF_SEPARATOR : NULL, dwMenuID, 
			pIHandler->GetUIElementName(iId)))
		{
			return false;
		}

		// Register the associated event and ID
		GetPluginManager()->AddHandlerForCmdID(pIAssociatedPlugin, iId, pIHandler);

		return true;
	}
	else
	{
		CLogFile::WriteLine("Can't find specified menu !");
		return false;
	}
	*/

	return true;
}

/*
//////////////////////////////////////////////////////////////////////////
int CEditorImpl::FindMenuItem(CMenu *pMenu, LPCTSTR pszMenuString)
{
	//////////////////////////////////////////////////////////////////////
	// FindMenuItem() will find a menu item string from the specified
	// popup menu and returns its position (0-based) in the specified 
	// popup menu. It returns -1 if no such menu item string is found
	//////////////////////////////////////////////////////////////////////

	int iCount, i;
	CString str;

  ASSERT(pMenu);
  ASSERT(::IsMenu(pMenu->GetSafeHmenu()));

  iCount = pMenu->GetMenuItemCount();

  for (i=0; i<iCount; i++)
  {
		if (pMenu->GetMenuString(i, str, MF_BYPOSITION) &&
			(strcmp(str, pszMenuString) == 0))
		{
      return i;
		}
  }

  return -1;
}
*/

/*
bool CEditorImpl::RegisterPluginToolTab(HWND hwndContainer, char *pszName)
{
	//////////////////////////////////////////////////////////////////////
	// Register a new tab with an UI container
	//////////////////////////////////////////////////////////////////////

	ASSERT(::IsWindow(hwndContainer));
	ASSERT(pszName);

	(CCryEditView *) ((CFrameWnd *) (AfxGetMainWnd())->
		GetActiveView())->RegisterPluginToolTab(hwndContainer, pszName);

	return true;
}

HWND CEditorImpl::GetToolbarTabContainer()
{
	//////////////////////////////////////////////////////////////////////
	// Return the window handle of the toolbar container
	//////////////////////////////////////////////////////////////////////

	return (CCryEditView *) ((CFrameWnd *) (AfxGetMainWnd())->
		GetActiveView())->GetToolTabContainerWnd();
}
*/

// Change the message in the status bar
void CEditorImpl::SetStatusText(const char * pszString) 
{
	if (!m_bMatEditMode && GetMainFrame())
		GetMainFrame()->SetStatusText(pszString);
};

bool CEditorImpl::CreateRootMenuItem(const char *pszName)
{
	//////////////////////////////////////////////////////////////////////
	// Create the root menu for the plugin
	//////////////////////////////////////////////////////////////////////
	/*

	CMenu *pMainMenu;
	
	IPlugin *pIAssociatedPlugin = GetPluginManager()->GetAssociatedPlugin();
	ASSERT(!IsBadReadPtr(pIAssociatedPlugin, sizeof(IPlugin)));

	// Get the main menu
	pMainMenu = AfxGetMainWnd()->GetMenu();

	// Insert the menu
	if (!pMainMenu->AppendMenu(MF_BYPOSITION | MF_POPUP | MF_STRING, 
		(UINT) pMainMenu->GetSafeHmenu(), pszName))
	{
		return false;
	}

	CLogFile::FormatLine("Root menu for plugin created ('%s')", pszName);
	*/

	return true;
}

//////////////////////////////////////////////////////////////////////////
int CEditorImpl::SelectRollUpBar( int rollupBarId )
{
	if (GetMainFrame())
		return GetMainFrame()->SelectRollUpBar( rollupBarId );
	else
		return 0;
}

//////////////////////////////////////////////////////////////////////////
int CEditorImpl::AddRollUpPage(int rollbarId,LPCTSTR pszCaption, class CDialog *pwndTemplate, 
		                                         bool bAutoDestroyTpl, int iIndex,bool bAutoExpand)
{
	if (!GetMainFrame())
		return 0;

	if (pwndTemplate && !pwndTemplate->m_hWnd)
	{
		if (IDYES == AfxMessageBox( _T("AddRollUpPage called with NULL window handle, Possibly not enough memory for window creation\r\nEditor is unstable and should be restarted.\r\nSave current level?"),MB_YESNO|MB_ICONERROR ))
		{
			SaveDocument();
		}
		return 0;
	}

	//CLogFile::FormatLine("Rollup page inserted ('%s')", pszCaption);
	if (!GetRollUpControl(rollbarId))
		return 0;
	// Preserve Focused window.
	HWND hFocusWnd = GetFocus();
	int id = GetRollUpControl(rollbarId)->InsertPage(pszCaption, pwndTemplate, bAutoDestroyTpl, iIndex,bAutoExpand);

	//GetRollUpControl(rollbarId)->ExpandPage(id,true,false);
	// Make sure focus stay in main wnd.
	if (hFocusWnd && GetFocus() != hFocusWnd)
		SetFocus(hFocusWnd);
	return id;
}

//////////////////////////////////////////////////////////////////////////
void CEditorImpl::RemoveRollUpPage(int rollbarId,int iIndex)
{
	if (!GetRollUpControl(rollbarId))
		return;
	GetRollUpControl(rollbarId)->RemovePage(iIndex);
}

//////////////////////////////////////////////////////////////////////////	
void CEditorImpl::ExpandRollUpPage(int rollbarId,int iIndex, BOOL bExpand)
{
	if (!GetRollUpControl(rollbarId))
		return;

	// Preserve Focused window.
	HWND hFocusWnd = GetFocus();

	GetRollUpControl(rollbarId)->ExpandPage(iIndex, bExpand);
	
	// Preserve Focused window.
	if (hFocusWnd && GetFocus() != hFocusWnd)
		SetFocus(hFocusWnd);
}

//////////////////////////////////////////////////////////////////////////
void CEditorImpl::EnableRollUpPage(int rollbarId,int iIndex, BOOL bEnable)
{
	if (!GetRollUpControl(rollbarId))
		return;

	// Preserve Focused window.
	HWND hFocusWnd = GetFocus();

	GetRollUpControl(rollbarId)->EnablePage(iIndex, bEnable);
	
	// Preserve Focused window.
	if (hFocusWnd && GetFocus() != hFocusWnd)
		SetFocus(hFocusWnd);
}

//////////////////////////////////////////////////////////////////////////
HWND CEditorImpl::GetRollUpContainerWnd(int rollbarId)
{
	if (!GetRollUpControl(rollbarId))
		return 0;
	return GetRollUpControl(rollbarId)->GetSafeHwnd();
}		

//////////////////////////////////////////////////////////////////////////
int CEditorImpl::GetEditMode()
{
	return m_currEditMode;
}

//////////////////////////////////////////////////////////////////////////
void CEditorImpl::SetEditMode( int editMode )
{
	m_currEditMode = (EEditMode)editMode;
	m_prevEditMode = m_currEditMode;
	AABB box( Vec3(0,0,0),Vec3(0,0,0) );
	SetSelectedRegion( box );

	if (GetEditTool() && !GetEditTool()->IsNeedMoveTool())
	{
		SetEditTool(0,true);
	}
	
	if (editMode == eEditModeMove || editMode == eEditModeRotate || editMode == eEditModeScale)
	{
		SetAxisConstrains( m_lastAxis[editMode] );
		SetReferenceCoordSys( m_lastCoordSys[editMode] );
	}
	Notify( eNotify_OnEditModeChange );
}

//////////////////////////////////////////////////////////////////////////
void CEditorImpl::SetOperationMode( EOperationMode mode )
{
	m_operationMode = mode;
	gSettings.operationMode = mode;
}

//////////////////////////////////////////////////////////////////////////
EOperationMode CEditorImpl::GetOperationMode()
{
	return m_operationMode;
}

//////////////////////////////////////////////////////////////////////////
void CEditorImpl::SetEditTool( CEditTool *tool,bool bStopCurrentTool )
{
	if (tool == 0)
	{
		// Replace tool with the object modify edit tool.
		if (m_pEditTool != 0 && m_pEditTool->IsKindOf(RUNTIME_CLASS(CObjectMode)))
		{
			// Do not change.
			return;
		}
		else
		{
			tool = new CObjectMode;
		}
	}

	if (tool)
	{
		if (!tool->Activate(m_pEditTool))
			return;
	}

	if (bStopCurrentTool)
	{
		if (m_pEditTool != tool && m_pEditTool != 0)
		{
			m_pEditTool->EndEditParams();
			SetStatusText( "Ready" );
		}
	}
	
	/*
	if (tool != 0 && m_pEditTool == 0)
	{
		// Tool set.
		m_currEditMode = eEditModeTool;
	}
	if (tool == 0 && m_pEditTool != 0)
	{
		// Tool set.
		m_currEditMode = m_prevEditMode;
	}
	*/

	m_pEditTool = tool;
	if (m_pEditTool)
	{
		m_pEditTool->BeginEditParams( this,0 );
	}

	// Make sure pick is aborted.
	if (tool != m_pickTool)
	{
		m_pickTool = 0;
	}
	Notify( eNotify_OnEditToolChange );
}

//////////////////////////////////////////////////////////////////////////
void CEditorImpl::SetEditTool( const CString &sEditToolName,bool bStopCurrentTool )
{
	CEditTool *pTool = GetEditTool();
	if (pTool && pTool->GetClassDesc())
	{
		// Check if alredy selected.
		if (stricmp(pTool->GetClassDesc()->ClassName(),sEditToolName) == 0)
			return;
	}

	IClassDesc *pClass = GetIEditor()->GetClassFactory()->FindClass( sEditToolName );
	if (!pClass)
	{
		Warning( "Editor Tool %s not registered.",(const char*)sEditToolName );
		return;
	}
	if (pClass->SystemClassID() != ESYSTEM_CLASS_EDITTOOL)
	{
		Warning( "Class name %s is not a valid Edit Tool class.",(const char*)sEditToolName );
		return;
	}
	CRuntimeClass *pRtClass = pClass->GetRuntimeClass();
	if (pRtClass && pRtClass->IsDerivedFrom(RUNTIME_CLASS(CEditTool)))
	{
		CEditTool *pEditTool = (CEditTool*)pRtClass->CreateObject();
		GetIEditor()->SetEditTool(pEditTool);
		return;
	}
	else
	{
		Warning( "Class name %s is not a valid Edit Tool class.",(const char*)sEditToolName );
		return;
	}
}
	
//////////////////////////////////////////////////////////////////////////
CEditTool* CEditorImpl::GetEditTool()
{
	return m_pEditTool;
}

//////////////////////////////////////////////////////////////////////////
ITransformManipulator* CEditorImpl::ShowTransformManipulator( bool bShow )
{
	if (bShow)
	{
		if (!m_pAxisGizmo)
		{
			m_pAxisGizmo = new CAxisGizmo;
			m_pAxisGizmo->AddRef();
			GetObjectManager()->GetGizmoManager()->AddGizmo( m_pAxisGizmo );
		}
		return m_pAxisGizmo;
	}
	else
	{
		// Hide gizmo.
		if (m_pAxisGizmo)
		{
			GetObjectManager()->GetGizmoManager()->RemoveGizmo( m_pAxisGizmo );
			m_pAxisGizmo->Release();
		}
		m_pAxisGizmo = 0;
	}
	return 0;
}

//////////////////////////////////////////////////////////////////////////
ITransformManipulator* CEditorImpl::GetTransformManipulator()
{
	return m_pAxisGizmo;
}

//////////////////////////////////////////////////////////////////////////
void CEditorImpl::SetAxisConstrains( AxisConstrains axisFlags )
{
	m_selectedAxis = axisFlags;
	m_lastAxis[m_currEditMode] = m_selectedAxis;
	m_viewMan->SetAxisConstrain( axisFlags );
	SetTerrainAxisIgnoreObjects( false );

	// Update all views.
	UpdateViews( eUpdateObjects,NULL );
}

//////////////////////////////////////////////////////////////////////////
AxisConstrains CEditorImpl::GetAxisConstrains()
{
	return m_selectedAxis;
}

//////////////////////////////////////////////////////////////////////////
void CEditorImpl::SetTerrainAxisIgnoreObjects( bool bIgnore )
{
	m_bTerrainAxisIgnoreObjects = bIgnore;
}

//////////////////////////////////////////////////////////////////////////
bool CEditorImpl::IsTerrainAxisIgnoreObjects()
{
	return m_bTerrainAxisIgnoreObjects;
}

//////////////////////////////////////////////////////////////////////////
void CEditorImpl::SetReferenceCoordSys( RefCoordSys refCoords )
{
	m_refCoordsSys = refCoords;
	m_lastCoordSys[m_currEditMode] = m_refCoordsSys;

	// Update all views.
	UpdateViews( eUpdateObjects,NULL );

	// Update the construction plane infos.
	CViewport *pViewport = GetActiveView();
	if(pViewport)
		pViewport->MakeConstructionPlane(GetIEditor()->GetAxisConstrains());
}

//////////////////////////////////////////////////////////////////////////
RefCoordSys CEditorImpl::GetReferenceCoordSys()
{
	return m_refCoordsSys;
}

//////////////////////////////////////////////////////////////////////////
CBaseObject* CEditorImpl::NewObject( const CString &typeName,const CString &file )
{
	SetModifiedFlag();
	GetIEditor()->SetModifiedModule(eModifiedBrushes);
	return GetObjectManager()->NewObject( typeName,0,file );
}

//////////////////////////////////////////////////////////////////////////
void CEditorImpl::DeleteObject( CBaseObject *obj )
{
	SetModifiedFlag();
	GetIEditor()->SetModifiedModule(eModifiedBrushes);
	GetObjectManager()->DeleteObject( obj );
}

//////////////////////////////////////////////////////////////////////////
CBaseObject* CEditorImpl::CloneObject( CBaseObject *obj )
{
	SetModifiedFlag();
	GetIEditor()->SetModifiedModule(eModifiedBrushes);
	return GetObjectManager()->CloneObject( obj );
}

//////////////////////////////////////////////////////////////////////////
void CEditorImpl::StartObjectCreation( const CString &type,const CString &file )
{
	CObjectCreateTool *pTool = new CObjectCreateTool;
	GetIEditor()->SetEditTool( pTool );
	pTool->StartCreation( type,file );
}

//////////////////////////////////////////////////////////////////////////
CBaseObject* CEditorImpl::GetSelectedObject()
{
	CBaseObject *obj = 0;
	if (m_objectMan->GetSelection()->GetCount() != 1)
		return 0;
	return m_objectMan->GetSelection()->GetObject(0);
}

//////////////////////////////////////////////////////////////////////////
void CEditorImpl::SelectObject( CBaseObject *obj )
{
	GetObjectManager()->SelectObject( obj );
}

//////////////////////////////////////////////////////////////////////////
IObjectManager* CEditorImpl::GetObjectManager()
{
	return m_objectMan;
};

//////////////////////////////////////////////////////////////////////////
CSettingsManager* CEditorImpl::GetSettingsManager()
{
	// Do not go any further before XML class is ready to use
	if (!gEnv)
		return NULL;

	if (!GetISystem())
		return NULL;
	
	if (!m_pSettingsManager)
	{
		m_pSettingsManager = new CSettingsManager(eSettingsManagerMemoryStorage);
	}

	return m_pSettingsManager;
}

//////////////////////////////////////////////////////////////////////////
CSelectionGroup* CEditorImpl::GetSelection()
{
	return m_objectMan->GetSelection();
}

//////////////////////////////////////////////////////////////////////////
int CEditorImpl::ClearSelection()
{
	return m_objectMan->ClearSelection();
}

//////////////////////////////////////////////////////////////////////////
void CEditorImpl::LockSelection( bool bLock )
{
	// Selection must be not empty to enable selection lock.
	if (!GetSelection()->IsEmpty())
		m_bSelectionLocked = bLock;
	else
		m_bSelectionLocked = false;
}

//////////////////////////////////////////////////////////////////////////
bool CEditorImpl::IsSelectionLocked()
{
	return m_bSelectionLocked;
}

//////////////////////////////////////////////////////////////////////////
void CEditorImpl::PickObject( IPickObjectCallback *callback,CRuntimeClass *targetClass,const char *statusText,bool bMultipick )
{
	m_pickTool = new CPickObjectTool(callback,targetClass);
	((CPickObjectTool*)m_pickTool)->SetMultiplePicks( bMultipick );
	if (statusText)
		m_pickTool->SetStatusText(statusText);

	SetEditTool( m_pickTool );
}

//////////////////////////////////////////////////////////////////////////
void CEditorImpl::CancelPick()
{
	SetEditTool(0);
	m_pickTool = 0;
}

//////////////////////////////////////////////////////////////////////////
bool CEditorImpl::IsPicking()
{
	if (GetEditTool() == m_pickTool && m_pickTool != 0)
		return true;
	return false;
}

//////////////////////////////////////////////////////////////////////////
CViewManager* CEditorImpl::GetViewManager()
{
	return m_viewMan;
}

CViewport* CEditorImpl::GetActiveView()
{
	if (!GetMainFrame())
		return 0;

	CLayoutViewPane* viewPane = (CLayoutViewPane*) GetMainFrame()->GetActiveView();
	if (viewPane)
	{
		CWnd *pWnd = viewPane->GetViewport();
		if (pWnd && pWnd->IsKindOf(RUNTIME_CLASS(CViewport)))
			return (CViewport*)pWnd;
	}
	return 0;
}

//////////////////////////////////////////////////////////////////////////
void CEditorImpl::UpdateViews( int flags,AABB *updateRegion )
{
	AABB prevRegion = m_viewMan->GetUpdateRegion();
	if (updateRegion)
		m_viewMan->SetUpdateRegion( *updateRegion );
	m_viewMan->UpdateViews( flags );
	if (updateRegion)
		m_viewMan->SetUpdateRegion( prevRegion );
}

//////////////////////////////////////////////////////////////////////////
void CEditorImpl::UpdateTrackView( bool bOnlyKeys )
{
	if (bOnlyKeys)
		Notify( eNotify_OnUpdateTrackViewKeys );
	else
		Notify( eNotify_OnUpdateTrackView );
}

//////////////////////////////////////////////////////////////////////////
void CEditorImpl::ResetViews()
{
	m_viewMan->ResetViews();

	m_displaySettings->SetRenderFlags( m_displaySettings->GetRenderFlags() );
}

//////////////////////////////////////////////////////////////////////////
float CEditorImpl::GetTerrainElevation( float x,float y )
{
	I3DEngine *engine = m_system->GetI3DEngine();
	if (!engine)
		return 0;
	return engine->GetTerrainElevation( x,y );
}

CHeightmap* CEditorImpl::GetHeightmap()
{
	return &CTerrainManager::GetTerrainManager().GetHeightmap();
}

CVegetationMap* CEditorImpl::GetVegetationMap()
{
	assert( GetHeightmap() != 0 );
	return GetHeightmap()->GetVegetationMap();
}

void CEditorImpl::SetSelectedRegion( const AABB &box )
{
	m_selectedRegion = box;
}
	
void CEditorImpl::GetSelectedRegion( AABB &box )
{
	box = m_selectedRegion;
}

//////////////////////////////////////////////////////////////////////////
CWnd* CEditorImpl::OpenView( const char *sViewName )
{
	if (!GetMainFrame())
		return 0;
	return GetMainFrame()->OpenPage( sViewName );
}

//////////////////////////////////////////////////////////////////////////
CWnd* CEditorImpl::FindView( const char *sViewName )
{
	if (!GetMainFrame())
		return 0;
	CMainFrame* pMainFrame = GetMainFrame();
	return pMainFrame ? pMainFrame->FindPage( sViewName ) : 0;
}

//////////////////////////////////////////////////////////////////////////
IDataBaseManager* CEditorImpl::GetDBItemManager( EDataBaseItemType itemType )
{
	switch (itemType)
	{
	case EDB_TYPE_MATERIAL:
		return m_materialManager;
	case EDB_TYPE_ENTITY_ARCHETYPE:
		return m_entityManager;
	case EDB_TYPE_PREFAB:
		return m_pPrefabManager;
	case EDB_TYPE_GAMETOKEN:
		return m_pGameTokenManager;
	case EDB_TYPE_PARTICLE:
		return m_particleManager;
	case EDB_TYPE_MUSIC:
		return m_pMusicManager;
	}
	return 0;
}

//////////////////////////////////////////////////////////////////////////
CBaseLibraryDialog* CEditorImpl::OpenDataBaseLibrary( EDataBaseItemType type,IDataBaseItem *pItem )
{
	if (pItem)
		type = pItem->GetType();

	CWnd *pWnd = NULL;
	if (type == EDB_TYPE_MATERIAL)
	{
		pWnd = OpenView( "Material Editor" );
	}
	else
	{
		pWnd = OpenView( "DataBase View" );
	}

	IDataBaseManager *pManager = GetDBItemManager(type);
	if (pManager)
		pManager->SetSelectedItem(pItem);

	if (pWnd && pWnd->IsKindOf(RUNTIME_CLASS(CBaseLibraryDialog)))
	{
		return (CBaseLibraryDialog*)pWnd;
	}
	if (pWnd && pWnd->IsKindOf(RUNTIME_CLASS(CDataBaseDialog)))
	{
		CDataBaseDialog *dlgDB = (CDataBaseDialog*)pWnd;
		CDataBaseDialogPage *pPage = dlgDB->SelectDialog( type,pItem );
		if (pPage && pPage->IsKindOf(RUNTIME_CLASS(CBaseLibraryDialog)))
		{
			return (CBaseLibraryDialog*)pPage;
		}
	}
	return 0;
}

//////////////////////////////////////////////////////////////////////////
bool CEditorImpl::SelectColor( COLORREF &color,CWnd *parent )
{
	COLORREF col = color;
	CCustomColorDialog dlg( col,CC_FULLOPEN,parent );
	if (dlg.DoModal() == IDOK)
	{
		color = dlg.GetColor();
		return true;
	}
	return false;
}

void CEditorImpl::SetInGameMode( bool inGame )
{
	if (m_gameEngine)
		m_gameEngine->SetGameMode(inGame);
}

bool CEditorImpl::IsInGameMode()
{
	if (m_gameEngine)
		return m_gameEngine->IsInGameMode();
	return false;
}

bool CEditorImpl::IsInTestMode()
{
	return ((CCryEditApp*)AfxGetApp())->IsInTestMode();
}

bool CEditorImpl::IsInConsolewMode()
{
	return ((CCryEditApp*)AfxGetApp())->IsInConsoleMode();
}

bool CEditorImpl::IsInLevelLoadTestMode()
{
	return ((CCryEditApp*)AfxGetApp())->IsInLevelLoadTestMode();
}

bool CEditorImpl::IsInPreviewMode()
{
	return ((CCryEditApp*)AfxGetApp())->IsInPreviewMode();
}

void CEditorImpl::EnableAcceleratos( bool bEnable )
{
	if (GetMainFrame())
		GetMainFrame()->EnableAccelerator( bEnable );
}

void CEditorImpl::DetectVersion()
{
	char exe[_MAX_PATH];
	DWORD dwHandle;
	UINT len;
	
	char ver[1024*8];
	
	GetModuleFileName( NULL, exe, _MAX_PATH );
	
	int verSize = GetFileVersionInfoSize( exe,&dwHandle );
	if (verSize > 0)
	{
		GetFileVersionInfo( exe,dwHandle,1024*8,ver );
		VS_FIXEDFILEINFO *vinfo;
		VerQueryValue( ver,"\\",(void**)&vinfo,&len );
		
		m_fileVersion.v[0] = vinfo->dwFileVersionLS & 0xFFFF;
		m_fileVersion.v[1] = vinfo->dwFileVersionLS >> 16;
		m_fileVersion.v[2] = vinfo->dwFileVersionMS & 0xFFFF;
		m_fileVersion.v[3] = vinfo->dwFileVersionMS >> 16;
		
		m_productVersion.v[0] = vinfo->dwProductVersionLS & 0xFFFF;
		m_productVersion.v[1] = vinfo->dwProductVersionLS >> 16;
		m_productVersion.v[2] = vinfo->dwProductVersionMS & 0xFFFF;
		m_productVersion.v[3] = vinfo->dwProductVersionMS >> 16;
		
		//debug( "<kernel> FileVersion: %d.%d.%d.%d",s_fileVersion.v[3],s_fileVersion.v[2],s_fileVersion.v[1],s_fileVersion.v[0] );
		//debug( "<kernel> ProductVersion: %d.%d.%d.%d",s_productVersion.v[3],s_productVersion.v[2],s_productVersion.v[1],s_productVersion.v[0] );
	}
}

XmlNodeRef CEditorImpl::FindTemplate( const CString &templateName )
{
	return m_templateRegistry.FindTemplate( templateName );
}
	
void CEditorImpl::AddTemplate( const CString &templateName,XmlNodeRef &tmpl )
{
	m_templateRegistry.AddTemplate( templateName,tmpl );
}

//////////////////////////////////////////////////////////////////////////
CShaderEnum* CEditorImpl::GetShaderEnum()
{
	return m_shaderEnum;
}

//////////////////////////////////////////////////////////////////////////
bool CEditorImpl::ExecuteConsoleApp( const CString &CommandLine, CString &OutputText )
{
	////////////////////////////////////////////////////////////////////////
	// Execute a console application and redirect its output to the
	// console window
	////////////////////////////////////////////////////////////////////////

	SECURITY_ATTRIBUTES sa = { 0 };
	STARTUPINFO si = { 0 };
	PROCESS_INFORMATION pi = { 0 };
	HANDLE hPipeOutputRead = NULL;
	HANDLE hPipeOutputWrite = NULL;
	HANDLE hPipeInputRead = NULL;
	HANDLE hPipeInputWrite = NULL;
	BOOL bTest = FALSE;
	bool bReturn = true;
	DWORD dwNumberOfBytesRead = 0;
	DWORD dwStartTime = 0;
	char szCharBuffer[65];
	char szOEMBuffer[65];

	CLogFile::FormatLine("Executing console application '%s'", (const char*)CommandLine);
	
	// Initialize the SECURITY_ATTRIBUTES structure
	sa.nLength = sizeof(SECURITY_ATTRIBUTES);
	sa.bInheritHandle = TRUE;
	sa.lpSecurityDescriptor = NULL;

	// Create a pipe for standard output redirection
	VERIFY(CreatePipe(&hPipeOutputRead, &hPipeOutputWrite, &sa, 0));

	// Create a pipe for standard inout redirection
	VERIFY(CreatePipe(&hPipeInputRead, &hPipeInputWrite, &sa, 0));

	// Make a child process useing hPipeOutputWrite as standard out. Also
	// make sure it is not shown on the screen
	si.cb = sizeof(STARTUPINFO);
	si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
	si.wShowWindow = SW_HIDE;
	si.hStdInput = hPipeInputRead;
	si.hStdOutput = hPipeOutputWrite;
	si.hStdError = hPipeOutputWrite;

	// Save the process start time
	dwStartTime = GetTickCount();

	// Launch the console application
	char cmdLine[1024];
	strcpy( cmdLine,CommandLine );
	if (!CreateProcess(NULL, cmdLine, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi))
		return false;

	// If no process was spawned
	if (!pi.hProcess)
		bReturn = false;

	// Now that the handles have been inherited, close them
	CloseHandle(hPipeOutputWrite);
	CloseHandle(hPipeInputRead);

	// Capture the output of the console application by reading from hPipeOutputRead
	while (true)
	{
		// Read from the pipe
		bTest = ReadFile(hPipeOutputRead, &szOEMBuffer, 64, &dwNumberOfBytesRead, NULL);

		// Break when finished
		if (!bTest)
			break;

		// Break when timeout has been exceeded
		if (GetTickCount() - dwStartTime > 5000)
			break;

		// Null terminate string
		szOEMBuffer[dwNumberOfBytesRead] = '\0';

		// Translate into ANSI
		VERIFY(OemToChar(szOEMBuffer, szCharBuffer));

		// Add it to the output text
		OutputText += szCharBuffer;
	}

	// Wait for the process to finish
	WaitForSingleObject(pi.hProcess, 1000);

	return bReturn;
}

//////////////////////////////////////////////////////////////////////////
// Undo
//////////////////////////////////////////////////////////////////////////
void CEditorImpl::BeginUndo()
{
	if (m_undoManager)
		m_undoManager->Begin();
}

//////////////////////////////////////////////////////////////////////////
void CEditorImpl::RestoreUndo( bool undo )
{
	if (m_undoManager)
		m_undoManager->Restore(undo);
}

//////////////////////////////////////////////////////////////////////////
void CEditorImpl::AcceptUndo( const CString &name )
{
	if (m_undoManager)
		m_undoManager->Accept(name);
}

//////////////////////////////////////////////////////////////////////////
void CEditorImpl::CancelUndo()
{
	if (m_undoManager)
		m_undoManager->Cancel();
}

//////////////////////////////////////////////////////////////////////////
void CEditorImpl::SuperBeginUndo()
{
	if (m_undoManager)
		m_undoManager->SuperBegin();
}

//////////////////////////////////////////////////////////////////////////
void CEditorImpl::SuperAcceptUndo( const CString &name )
{
	if (m_undoManager)
		m_undoManager->SuperAccept(name);
}

//////////////////////////////////////////////////////////////////////////
void CEditorImpl::SuperCancelUndo()
{
	if (m_undoManager)
		m_undoManager->SuperCancel();
}

//////////////////////////////////////////////////////////////////////////
void CEditorImpl::SuspendUndo()
{
	if (m_undoManager)
		m_undoManager->Suspend();
}

//////////////////////////////////////////////////////////////////////////
void CEditorImpl::ResumeUndo()
{
	if (m_undoManager)
		m_undoManager->Resume();
}

//////////////////////////////////////////////////////////////////////////
void CEditorImpl::Undo()
{
	if (m_undoManager)
		m_undoManager->Undo();
}

//////////////////////////////////////////////////////////////////////////
void CEditorImpl::Redo()
{
	if (m_undoManager)
		m_undoManager->Redo();
}

//////////////////////////////////////////////////////////////////////////
bool CEditorImpl::IsUndoRecording()
{
	if (m_undoManager)
		return m_undoManager->IsUndoRecording();
	return false;
}

//////////////////////////////////////////////////////////////////////////
bool CEditorImpl::IsUndoSuspended()
{
	if (m_undoManager)
		return m_undoManager->IsUndoSuspended();
	return false;
}

//////////////////////////////////////////////////////////////////////////
void CEditorImpl::RecordUndo( IUndoObject *obj )
{
	if (m_undoManager)
		m_undoManager->RecordUndo( obj );
}

//////////////////////////////////////////////////////////////////////////
bool CEditorImpl::FlushUndo(bool isShowMessage)
{
	if(isShowMessage && m_undoManager && m_undoManager->IsHaveUndo() && AfxMessageBox("After this operation undo will not be available! Are you sure you want to continue?", MB_ICONQUESTION | MB_YESNO)!=IDYES)
		return false;

	if (m_undoManager)
		m_undoManager->Flush();
	return true;
}

//////////////////////////////////////////////////////////////////////////
void CEditorImpl::SetConsoleVar( const char *var,float value )
{
	ICVar *ivar = GetSystem()->GetIConsole()->GetCVar( var );
	if (ivar)
		ivar->Set( value );
}

//////////////////////////////////////////////////////////////////////////
float CEditorImpl::GetConsoleVar( const char *var )
{
	ICVar *ivar = GetSystem()->GetIConsole()->GetCVar( var );
	if (ivar)
	{
		return ivar->GetFVal();
	}
	return 0;
}

//////////////////////////////////////////////////////////////////////////
CAIManager*	CEditorImpl::GetAI()
{
	return m_pAI;
}

//////////////////////////////////////////////////////////////////////////
CAnimationContext* CEditorImpl::GetAnimation()
{
	return m_animationContext;
}

//////////////////////////////////////////////////////////////////////////
void CEditorImpl::RegisterDocListener( IDocListener *listener )
{
	CCryEditDoc *doc = GetDocument();
	if (doc)
	{
		doc->RegisterListener( listener );
	}
}

//////////////////////////////////////////////////////////////////////////
void CEditorImpl::UnregisterDocListener( IDocListener *listener )
{
	CCryEditDoc *doc = GetDocument();
	if (doc)
	{
		doc->UnregisterListener( listener );
	}
}

//////////////////////////////////////////////////////////////////////////
void CEditorImpl::Notify( EEditorNotifyEvent event )
{
	if (m_bExiting)
		return;

	std::list<IEditorNotifyListener*>::iterator it = m_listeners.begin();
	while (it != m_listeners.end())
	{
		(*it++)->OnEditorNotifyEvent(event);
	}
	if (event == eNotify_OnBeginNewScene)
	{
		if (m_pAxisGizmo)
			m_pAxisGizmo->Release();
		m_pAxisGizmo = 0;
	}

	if (event == eNotify_OnInit)
	{
#ifndef DISABLE_VICON
		//////////////////////////////////////////////////////////////////////////	
		REGISTER_COMMAND("Vicon_Connect", CmdViconConnect,0,"Connects to Vicon server.");
		REGISTER_COMMAND("Vicon_Disconnect", CmdViconDisconnect,0,"Disconnects from Vicon server.");	
		REGISTER_CVAR(m_fViconScale, 1.0f, VF_NULL,"Scale from Vicon to our Joystick system");	

		REGISTER_CVAR(m_fViconBend, 0.001f, VF_NULL,"Bending biped spine (Vicon)");	
		REGISTER_CVAR(m_fViconScale, 1.0f, VF_NULL,"Scale from Vicon to our Joystick system");	

		//////////////////////////////////////////////////////////////////////////

		m_ViconClient=new CViconClient(this);
#endif

		REGISTER_CVAR(doc_use_subfolder_for_crash_backup, 0, VF_NULL,"When saving a level after the editor has crashed, save to a sub-folder instead of overwriting the level");	
	}
}

//////////////////////////////////////////////////////////////////////////
void CEditorImpl::RegisterNotifyListener( IEditorNotifyListener *listener )
{
	stl::push_back_unique(m_listeners,listener);
}

//////////////////////////////////////////////////////////////////////////
void CEditorImpl::UnregisterNotifyListener( IEditorNotifyListener *listener )
{
	m_listeners.remove(listener);
}

//////////////////////////////////////////////////////////////////////////
ISourceControl* CEditorImpl::GetSourceControl()
{
	return m_pSourceControl->GetSCMInterface();
}
void CEditorImpl::SetMatEditMode(bool bIsMatEditMode)
{
	m_bMatEditMode = bIsMatEditMode;
}

//////////////////////////////////////////////////////////////////////////
void CEditorImpl::GetMemoryUsage( ICrySizer *pSizer )
{
	SIZER_COMPONENT_NAME( pSizer, "Editor" );

	if(GetDocument())
	{
		SIZER_COMPONENT_NAME( pSizer, "Document" );

		GetDocument()->GetMemoryUsage(pSizer);
	}
}

//////////////////////////////////////////////////////////////////////////
void CEditorImpl::ReduceMemory()
{
	GetIEditor()->GetUndoManager()->ClearRedoStack();
	GetIEditor()->GetUndoManager()->ClearUndoStack();
	GetIEditor()->GetObjectManager()->SendEvent( EVENT_FREE_GAME_DATA );
	gEnv->pRenderer->FreeResources( FRR_TEXTURES );

	HANDLE hHeap = GetProcessHeap();
	if (hHeap)
	{
		uint64 maxsize = (uint64)HeapCompact(hHeap,0);
		CryLogAlways( "Max Free Memory Block = %I64d Kb",maxsize/1024 );
	}
}

//////////////////////////////////////////////////////////////////////////
IFacialEditor* CEditorImpl::GetFacialEditor(bool openIfNecessary)
{
	CWnd* facialEditorWindow = 0;
	if (openIfNecessary)
		facialEditorWindow = ((CMainFrame*)AfxGetMainWnd())->OpenPage("Facial Editor");
	else
		facialEditorWindow = ((CMainFrame*)AfxGetMainWnd())->FindPage("Facial Editor");
	CFacialEditorDialog* facialEditor = (facialEditorWindow ? (CFacialEditorDialog*)facialEditorWindow : 0);
	IFacialEditor* facialEditorInterface = (facialEditor ? facialEditor : 0);
	return facialEditorInterface;
}

//////////////////////////////////////////////////////////////////////////
void CEditorImpl::AddUIEnums()
{
	// Add global enum for surface types.
	std::vector<CString> types;
	types.push_back(""); // Push empty surface type.
	ISurfaceTypeEnumerator *pSurfaceTypeEnum = Get3DEngine()->GetMaterialManager()->GetSurfaceTypeManager()->GetEnumerator();
	for(ISurfaceType *pSurfaceType = pSurfaceTypeEnum->GetFirst(); pSurfaceType; pSurfaceType = pSurfaceTypeEnum->GetNext())
		types.push_back(pSurfaceType->GetName());
	std::sort( types.begin(),types.end() );
	m_pUIEnumsDatabase->SetEnumStrings( "Surface", types );

	// Spec settings for shadow casting lights
	string SpecString[5];
	types.clear();
	types.push_back("Never=0");
	SpecString[0].Format("Detail Spec=%d",CONFIG_DETAIL_SPEC);
	//types.push_back(SpecString[0].c_str());						// Commented out since not used in SDK
	SpecString[1].Format("V.High Spec=%d",CONFIG_VERYHIGH_SPEC);
	types.push_back(SpecString[1].c_str());
	SpecString[2].Format("High Spec=%d",CONFIG_HIGH_SPEC);
	types.push_back(SpecString[2].c_str());



	SpecString[3].Format("Console/Med=%d",CONFIG_MEDIUM_SPEC);

	types.push_back(SpecString[3].c_str());
	SpecString[4].Format("Low Spec=%d",CONFIG_LOW_SPEC );
	types.push_back(SpecString[4].c_str());

	m_pUIEnumsDatabase->SetEnumStrings( "CastShadows", types );

	
	// Light shafts and lens ghosts
	string specName[5];
	types.clear();
		specName[0].Format("Max Spec=%d",eSQ_Max);
	types.push_back(specName[0].c_str());
		specName[1].Format("Very High Spec=%d",eSQ_VeryHigh);
	types.push_back(specName[1].c_str());
		specName[2].Format("High Spec=%d",eSQ_High);
	types.push_back(specName[2].c_str());
		specName[3].Format("Med Spec=%d",eSQ_Medium);
	types.push_back(specName[3].c_str());
		specName[4].Format("Low Spec=%d",eSQ_Low);
	types.push_back(specName[4].c_str());
	
	m_pUIEnumsDatabase->SetEnumStrings( "CoronaShaftsMinSpec", types );
	m_pUIEnumsDatabase->SetEnumStrings( "LensGhostsMinSpec", types );
}

//////////////////////////////////////////////////////////////////////////
// Set current configuration spec of the editor.
void CEditorImpl::SetEditorConfigSpec( ESystemConfigSpec spec )
{
	gSettings.editorConfigSpec = spec;
	if (m_system->GetConfigSpec(true) != spec)
	{
		m_system->SetConfigSpec( spec,true );
		gSettings.editorConfigSpec = m_system->GetConfigSpec(true);
		Notify( eNotify_OnConfigSpecChange );
		GetObjectManager()->SendEvent( EVENT_CONFIG_SPEC_CHANGE );
	}
}

//////////////////////////////////////////////////////////////////////////
ESystemConfigSpec CEditorImpl::GetEditorConfigSpec() const
{
	return (ESystemConfigSpec)gSettings.editorConfigSpec;
}

//////////////////////////////////////////////////////////////////////////
void CEditorImpl::InitFinished()
{
	if (!m_bInitialized)
	{
		m_bInitialized = true;
		Notify( eNotify_OnInit );

		// Let system wide listeners know about this as well.
		GetISystem()->GetISystemEventDispatcher()->OnSystemEvent(ESYSTEM_EVENT_EDITOR_ON_INIT, 0, 0);
	}
}

//////////////////////////////////////////////////////////////////////////
void CEditorImpl::ReloadTemplates()
{
	m_templateRegistry.LoadTemplates( Path::MakeFullPath("Editor") );
}

//////////////////////////////////////////////////////////////////////////
CConsoleSynchronization* CEditorImpl::GetConsoleSync()
{
	if(!m_pConsoleSync)
	{
		m_pConsoleSync = new CConsoleSynchronization();
	}
	return m_pConsoleSync;
}

//////////////////////////////////////////////////////////////////////////
HANDLE CEditorImpl::AsyncRunResourceCompiler(const char* szFileName, 
	const char* szAdditionalSettings, 
	bool bMayShowWindow, 
	bool bSilent,
	bool bNoUserDialog,
	const wchar_t* szWorkingDirectory)
{
	CResourceCompilerHelper rcHelper;
	return rcHelper.AsyncCallResourceCompiler(szFileName, szAdditionalSettings,
		bMayShowWindow, CResourceCompilerHelper::eRcExePath_registry, bSilent, 
		bNoUserDialog, szWorkingDirectory);
}

//////////////////////////////////////////////////////////////////////////
CSWManager* CEditorImpl::GetSegmentedWorldManager()
{
	return &CSWManager::Get();
}
